/**
 * Copyright (C), 2015-2019, XXX有限公司
 * FileName: SysLogAspect
 * Author:   Administrator
 * Date:     2019/12/20 22:08
 * Description: 日志拦截器
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.lumeng.spring.common.aspect;

import com.lumeng.spring.common.annotation.SysLog;
import com.lumeng.spring.common.factory.ClassRefletInterceptHandlerFactory;
import com.lumeng.spring.common.handler.LoggerInterceptorHandler;
import com.lumeng.spring.common.utils.IpAdrressUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.dc.pr.PRException;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 功能描述:
 * <日志拦截器>
 *
 * @program: etc_issue
 * @ClassName: SysLogAspect
 * @author: wanghui
 * @date: 2019/12/20 22:08
 * @Version: 1.0.0
 * @Copyright: 2019 Inc. All rights reserved. 注意: 本内容仅限于内部传阅,禁止外泄以及用于其他的商业目
 */
@Aspect
@Component
public class SysLogAspect {

    private AtomicReference<LoggerInterceptorHandler> handlerAtomicReference= new AtomicReference<>();

    @Pointcut("@annotation(com.lumeng.spring.common.annotation.SysLog)")
    public void controllerAspect() {}

    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Exception {
        Object result = null;
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Long traceId = StringUtils.isNotEmpty(request.getParameter("traceId"))?
                Long.parseLong(request.getParameter("traceId")):
                StringUtils.isNotEmpty(request.getHeader("traceId"))?
                        Long.parseLong(request.getHeader("traceId")):System.currentTimeMillis();
        request.setAttribute("traceId",traceId);

        String remoteIp = IpAdrressUtil.getRemoteIpAdrress(request);
        String localIp = IpAdrressUtil.getLocalHostAddress();
        Object target= joinPoint.getTarget();
        String targetName = target.getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Class[] methods= ((MethodSignature)joinPoint.getSignature()).getParameterTypes();
        Object[] arguments = joinPoint.getArgs();
        Class<?> clazz= target.getClass();
        LoggerInterceptorHandler interceptorHandler= this.handlerAtomicReference.get();
        String description = null;
        try {
            Method method=clazz.getMethod(methodName,methods);
            if(!isContainer(method)){
                return joinPoint.proceed();
            }
            description = getControllerMethodDescription(joinPoint);;
            //判断是否加载了日志输出类
            if (interceptorHandler==null){
                //初始化日志输出类
                interceptorHandler= new ClassRefletInterceptHandlerFactory(LoggerInterceptorHandler.LOGGER_ADDRESS).instance();
                this.handlerAtomicReference.set(interceptorHandler);
            }
            Object memberNo = request.getAttribute("memberNo");
            Object obj = request.getSession().getAttribute("loginUser");
            //输出开始日志
            interceptorHandler.interptBefore(traceId,remoteIp,localIp,description,targetName,methodName,arguments);
            //执行方法
            result= joinPoint.proceed();
            //输出结果日志
            interceptorHandler.interceptPost(traceId,remoteIp,localIp,description,targetName,methodName,result);
            return result;
        } catch (Throwable e) {
            e.fillInStackTrace();
            interceptorHandler.interptThrowing(traceId,remoteIp,localIp,description,targetName,methodName,e);
            throw new PRException(e.getMessage());
        }finally {
            interceptorHandler.interptFinally(traceId,remoteIp,localIp,description,targetName,methodName,traceId);
        }
    }

    @SuppressWarnings("rawtypes")
    private static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description = method.getAnnotation(SysLog.class).value();
                    break;
                }
            }
        }
        return description;
    }

    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        return attributes.getRequest();
    }

    private boolean isContainer(Method method){
        SysLog sysLog= method.getAnnotation(SysLog.class);
        return sysLog!=null;
    }
}
